/*
 * Copyright 2014-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

<template>
  <div v-loading="loading" class="contract-code" :class="{changeActive:changeWidth }">
    <div class="contract-code-head">
      <span v-show="codeShow" class="contract-code-title" :class="{titleActive:changeWidth }">
        <span>{{ contractName + '.sol' }}</span>
      </span>
      <span v-show="codeShow" class="contract-code-handle">

        <!-- 需要有查看权限才能显示操作按钮 -->
        <span v-show="ViewContractPermission === true">
          <span v-if="(!contractAddress && !disabled) || (contractAddress && !disabled &&isDeployedModifyEnable)" class="contract-code-done noBlur" @click="saveCode">
            <el-tooltip class="item" effect="dark" :content="$t('contracts.contractSaveTips')" placement="top-start">
              <i class="wbs-icon-baocun font-16" />
            </el-tooltip>
            <span>{{ this.$t("text.save") }}</span>
          </span>
          <span v-if="(!contractAddress && !disabled && !loading )|| (contractAddress && !disabled && !loading &&isDeployedModifyEnable)" class="contract-code-done noBlur" @click="compile">
            <i class="wbs-icon-bianyi font-16" />
            <span>{{ this.$t("text.compile") }}</span>
          </span>
          <span v-if="(!contractAddress && abiFile && bin && !disabled)|| (contractAddress && !disabled &&isDeployedModifyEnable)" class="contract-code-done" @click="deploying">
            <i class="wbs-icon-deploy font-16" />
            <span>{{ this.$t("text.deploy") }}</span>
          </span>
          <span v-if="abiFile && bin && !disabled" class="contract-code-done" @click="send">
            <i class="wbs-icon-send font-16" />
            <span>{{ this.$t("text.send") }}</span>
          </span>
          <!-- <span v-if="(!contractAddress && abiFile && bin && !disabled)|| (contractAddress && !disabled)" class="contract-code-done" @click="exportJava">
            <i class="el-icon-download contract-icon-style font-16" />
            <span>{{ this.$t("text.exportJavaProject") }}</span>
          </span> -->

        </span>
        <el-button
          type="primary"
          class="uploadReportBtn"
          @click="onUploadReport"
        >
          <el-image
            class="uploadReportIcon"
            style="width: 13px; height: 14px"
            :src="require('@/assets/report/uploadReportIcon.png')"
          />
          提交报告</el-button>
      </span>
    </div>
    <div class="contract-code-content" :class="{infoHide: !successHide}">
      <div ref="codeContent" class="contract-code-mirror" :style="{height:codeHight}">
        <!-- 显示空白提示 -->
        <div v-show="codeShow === false && ViewContractPermission === true" style="padding-top: 60px;text-align:center;">
          <span>{{ this.$t("contracts.contractOpenTips") }}</span>
          <!-- <span>{{ this.$t("contracts.createContractTips") }}</span> -->
          <!-- <i class="wbs-icon-shangchuan" /> -->
          <span>{{ this.$t("contracts.uploadContractTips") }}</span>
          <strong><i class="wbs-icon-Addfile" /></strong>
        </div>

        <!-- 没有权限查看这个 -->
        <div v-show="ViewContractPermission === false" style="padding-top: 60px;text-align:center;">
          <span>暂无合约查看权限</span>
        </div>

        <!-- 显示编辑器 -->
        <div v-show="codeShow === true && ViewContractPermission === true" ref="ace" class="ace-editor" />
      </div>

      <!-- 底部链信息，需要有查看权限 -->
      <div v-show="successHide === true && ViewContractPermission === true" class="contract-info" :style="{height:infoHeight + 'px'}">
        <div class="move" @mousedown="dragDetailWeight($event)" @mouseup="resizeCode" />
        <div v-show="abiFile||contractAddress" class="contract-info-title" @mouseover="mouseHover=!mouseHover" @mouseout="mouseHover=!mouseHover">
          <i :class="[showCompileText?'el-icon-caret-bottom':'el-icon-caret-top']" @click="collapse" />

        </div>
        <div>
          <div class="contract-info-list1" v-html="compileinfo" />
          <div v-show="errorInfo" class="contract-info-list1 error-item" style="color: #f00">
            <!-- <span style="display:inline-block;width:calc(100% - 120px);word-wrap:break-word" v-for="(item, index) in errorMessage" :style="{'color' : severityColor(item)}">
                            {{index+1}}: {{item | formatErrorMessage}}
                            <i class="el-icon-circle-plus-outline" @click="optenErrorInfo(item, index)"></i>{{item | formatErrorMessage}}
                            <span style="display:inline-block;width:calc(100% - 120px);word-wrap:break-word" v-if="item.open">
                                <span>
                                    <pre>{{item}}</pre>
                                </span>
                            </span>
                        </span> -->
            <el-collapse v-model="activeNames" @change="handleChange">
              <el-collapse-item v-for="(item, index) in errorMessage" :key="index" :name="index" :style="{'color': severityColor(item)}">
                <template slot="title">
                  {{ index+1 }}、{{ item | formatErrorMessage }}
                </template>
                <span style="display:inline-block;width:calc(100% - 120px);word-wrap:break-word;">
                  <span>
                    <pre :style="{'color': severityColor(item)}">{{ item }}</pre>
                  </span>
                </span>
              </el-collapse-item>

            </el-collapse>
          </div>
          <div v-show="abiFileShow" style="color: #68E600;padding-bottom: 15px;">{{ successInfo }}</div>
          <div v-if="contractAddress" class="contract-info-list">
            <span class="contract-info-list-title" style="color: #0B8AEE">contractAddress
              <i class="wbs-icon-copy font-12 copy-public-key" :title="$t('text.copy')" @click="copyKey(contractAddress)" />
            </span>
            <span style="display:inline-block;width:calc(100% - 120px);word-wrap:break-word">
              {{ contractAddress }}
              <span v-if="reqVersion" style="margin-left: 10px;">(CNS: {{ cnsName }} {{ reqVersion }})</span>
              <span v-else style="color:#1f83e7;cursor: pointer;margin-left: 10px;" @click="handleRegisterCns">{{ $t('text.register') }}</span>
            </span>
          </div>
          <div v-else v-show="abiFile" class="contract-info-list">
            <span v-if="!abiEmpty" class="contract-info-list-title" style="color: #0B8AEE">contractAddress
            </span>
            <span v-if="!abiEmpty" style="color:#1f83e7;cursor: pointer;margin-left: 10px;" @click="addContractAddress">{{ $t('text.addContractAddress') }}</span>
          </div>
          <div v-show="abiFile" class="contract-info-list">
            <span class="contract-info-list-title" style="color: #0B8AEE">contractName
              <i class="wbs-icon-copy font-12 copy-public-key" :title="$t('text.copy')" @click="copyKey(contractName)" /> </span>
            <span style="display:inline-block;width:calc(100% - 120px);word-wrap:break-word">{{ contractName }}</span>
          </div>
          <div v-show="abiFile" class="contract-info-list">
            <span class="contract-info-list-title" style="color: #0B8AEE">abi
              <i class="wbs-icon-copy font-12 copy-public-key" :title="$t('text.copy')" @click="copyKey(abiFile)" />
            </span>
            <span ref="showAbiText" class="showText">
              {{ abiFile }}
            </span>
            <i v-if="complieAbiTextHeight" :class="[ showAbi ? 'el-icon-arrow-down': 'el-icon-arrow-up','font-13','cursor-pointer','visibility-wrapper'] " @click="showAbiText" />
          </div>
          <div v-show="abiFile" class="contract-info-list" style="border-bottom: 1px solid #e8e8e8">
            <span class="contract-info-list-title" style="color: #0B8AEE">bytecodeBin
              <i class="wbs-icon-copy font-12 copy-public-key" :title="$t('text.copy')" @click="copyKey(bytecodeBin)" />
            </span>
            <span ref="showBinText" class="showText">
              {{ bytecodeBin }}
            </span>
            <i v-if="complieBinTextHeight" :class="[ showBin ? 'el-icon-arrow-down': 'el-icon-arrow-up','font-13','cursor-pointer','visibility-wrapper'] " @click="showBinText" />
          </div>
        </div>
      </div>
    </div>

    <!-- 发送交易弹窗 -->
    <el-dialog v-if="dialogVisible" v-dialogDrag :title="$t('contracts.sendTransaction')" :visible.sync="dialogVisible" width="580px" :before-close="sendClose" center class="send-dialog">
      <v-transaction ref="send" :data="data" :abi="abiFile" :version="version" :address="uploadAddress" @success="sendSuccess($event)" @close="handleClose" />
    </el-dialog>

    <!-- 部署弹窗 -->
    <el-dialog v-if="dialogUser" v-dialogDrag :title="$t('contracts.changeUser')" :visible.sync="dialogUser" width="550px" center class="send-dialog">
      <v-user :abi="abiFile" :contract-name="contractName" @change="deployContract(arguments)" @close="userClose" />
    </el-dialog>

    <v-editor v-if="editorShow" :show="editorShow" :data="editorData" :input="editorInput" :editor-output="editorOutput" :send-constant="sendConstant" @close="editorClose" />
    <v-upload v-if="uploadFileAdrShow" :show="uploadFileAdrShow" @close="uploadClose" @success="uploadSuccess($event)" />
    <el-dialog v-if="mgmtCnsVisible" :title="$t('text.cns')" :visible.sync="mgmtCnsVisible" width="470px" center class="send-dialog">
      <mgmt-cns :mgmt-cns-item="mgmtCnsItem" @mgmtCnsResultSuccess="mgmtCnsResultSuccess($event)" @mgmtCnsResultClose="mgmtCnsResultClose" />
    </el-dialog>
    <el-dialog v-if="addContractAddressVisible" :visible.sync="addContractAddressVisible" :title="$t('dialog.addContractAddress')" width="400px" class="dialog-wrapper" center>
      <el-form ref="contractForm" :rules="rules" :model="contractForm">
        <el-form-item label="" prop="contractAddress">
          <el-input v-model="contractForm.contractAddress" :placeholder="$t('contracts.contractAddressInput')" />
        </el-form-item>
      </el-form>
      <div slot="footer" class="text-right">
        <el-button @click="closeContractAddress">{{ $t('dialog.cancel') }}</el-button>
        <el-button type="primary" @click="sureContractAddress('contractForm')">{{ $t('dialog.confirm') }}</el-button>
      </div>
    </el-dialog>

    <uploadReport ref="uploadReport" :visible="isShowUploadReport" @close="onCloseUploadReport" />
  </div>
</template>

<script>
import ace from 'ace-builds'
// require("ace-builds/webpack-resolver");
import 'ace-builds/webpack-resolver'
import 'ace-builds/src-noconflict/theme-chrome'
import 'ace-builds/src-noconflict/mode-javascript'
import 'ace-builds/src-noconflict/ext-language_tools'
require('ace-mode-solidity/build/remix-ide/mode-solidity')
const Mode = require('ace-mode-solidity/build/remix-ide/mode-solidity').Mode
import errcode from '@/utils/errcode'
const Base64 = require('js-base64').Base64
import constant from '@/utils/constant'
import editor from '@/components/editor'
import uploadFileAdr from '../dialog/uploadFileAdr'
import uploadReport from './uploadReport'
import Bus from '@/bus'
import web3 from '@/utils/ethAbi'
import router from '@/router'

// import javascriptWorkerUrl from "file-loader?esModule=false!./src-noconflict/worker-javascript.js";
// ace.config.setModuleUrl("ace/mode/json_worker", javascriptWorkerUrl);
import {
  getDeployStatus,
  addFunctionAbi,
  registerCns,
  findCnsInfo,
  fetchIsDeployedModifyEnable,
  getViewContractPermissions,
  getEditContractPermissions
} from '@/api/exercises'
import transaction from '@/components/sendTransaction'
import changeUser from '../dialog/changeUser'
import mgmtCns from '../dialog/mgmtCns'

export default {
  name: 'Codes',
  components: {
    'v-transaction': transaction,
    'v-user': changeUser,
    'v-editor': editor,
    'v-upload': uploadFileAdr,
    mgmtCns,
    uploadReport
  },
  props: ['show', 'changeStyle'],
  data: function() {
    return {
      isShowUploadReport: false,
      successHide: true,
      loading: false,
      content: '',
      successShow: true,
      errorShow: false,
      dialogVisible: false,
      code: '',
      status: 0,
      abiFile: '',
      // abi is empty list
      abiEmpty: true,
      bin: '',
      contractAddress: '',
      contractName: '',
      infoHeight: 250,
      contractList: [],
      dialogUser: false,
      compileinfo: '',
      errorInfo: '',
      errorMessage: '',
      successInfo: '',
      abiFileShow: false,
      bytecodeBin: '',
      aceEditor: null,
      themePath: 'ace/theme/chrome',
      modePath: 'ace/mode/solidity',
      data: null,
      codeShow: false,
      version: '',
      saveShow: false,
      editorShow: false,
      editorData: null,
      editorInput: null,
      editorOutput: null,
      uploadFileAdrShow: false,
      uploadAddress: '',
      disabled: false,
      showAbi: true,
      showBin: true,
      complieAbiTextHeight: false,
      complieBinTextHeight: false,
      mouseHover: false,
      showCompileText: true,
      sendConstant: null,
      reqVersion: '',
      cnsName: '',
      mgmtCnsVisible: false,
      mgmtCnsItem: {},
      activeNames: ['0'],
      isDeployedModifyEnable: false, // 保存、部署、编译 开关
      isFinishComplie: false,
      addContractAddressVisible: false,
      contractForm: {
        contractAddress: ''
      },
      rules: {
        contractAddress: [
          {
            required: true,
            message: this.$t('rule.contractAddress'),
            trigger: 'blur'
          },
          {
            pattern: /^[0x|0X]+[A-Fa-f0-9]+$/,
            message: this.$t('rule.contractAddressHex'),
            trigger: 'blur'
          },
          {
            min: 42,
            max: 42,
            message: this.$t('rule.contractAddressLong'),
            trigger: 'blur'
          }
        ]
      },
      ViewContractPermission: null,
      EditContractPermission: null
    }
  },
  computed: {
    codeHight: function() {
      if (this.infoHeight) {
        return `calc(100% - ${this.infoHeight}px)`
      } else {
        return `100%`
      }
    },
    changeWidth() {
      if (this.changeStyle) {
        return this.changeStyle
      } else {
        return false
      }
    },
    tipShow() {
      return !this.show
    }
  },
  watch: {
    content: function(val) {
      const data = Base64.decode(this.data.contractSource)
      if (data != val) {
        this.saveShow = true
      } else {
        this.saveShow = false
      }
    },
    successHide: function(val) {
      if (val) {
        this.infoHeight = 250
      } else {
        this.infoHeight = 0
      }
    }
  },
  beforeDestroy: function() {
    Bus.$off('select')
    Bus.$off('noData')
    Bus.$off('javaProjectComplie')
  },
  beforeMount() {

  },
  mounted: function() {
    // 实训平台权限
    this.handleContractPermissions()

    // if (localStorage.getItem('root') === 'admin' || localStorage.getItem('root') === 'developer') {
    // this.disabled = false
    // } else {
    //   this.disabled = true
    // }

    // 状态
    this.queryIsDeployedModifyEnable()

    // 初始化编辑器
    this.initEditor()

    Bus.$on('langChange', (item) => {
      if (item == 1) {
        this.modePath = 'ace/mode/rust'
      } else {
        this.modePath = 'ace/mode/solidity'
      }
      this.aceEditor.session.setMode(this.modePath)
    // this.initEditor();
    })

    // 初始化信息
    Bus.$on('select', data => {
      console.log('初始化信息')
      console.log(data)
      this.codeShow = true
      this.refreshMessage()
      // 初始化数据
      this.code = ''
      this.version = ''
      this.status = null
      this.abiFile = ''
      this.abiEmpty = true
      this.contractAddress = ''
      this.errorMessage = ''
      this.contractName = ''
      this.content = ''
      this.bin = ''

      // 赋值数据
      this.data = data // 从后台接受到的数据
      this.code = Base64.decode(data.contractSource) // 使用base64完成解谜
      this.content = this.code
      this.aceEditor.setValue(this.content) // 设置 ACE 编辑器内容
      this.status = data.contractStatus // 合约状态
      this.abiFile = data.contractAbi// 合约api，在链信息处同步
      if (this.abiFile && this.abiFile != '[]') {
        // 是否空白，状态改为有内容
        this.abiEmpty = false
      }
      this.contractAddress = data.contractAddress // 合约地址
      this.errorMessage = data.description || '' // 描述
      this.contractName = data.contractName // 合约名称
      this.bin = data.contractBin // 合约 Bin
      this.bytecodeBin = data.bytecodeBin || '' // 链信息：bytecodeBin
      this.version = data.contractVersion // 合约版本
      this.complieAbiTextHeight = false
      this.complieBinTextHeight = false
      if (this.data.contractAddress) {
        // 目前没发现作用
        this.queryFindCnsInfo()
      }
    })
    Bus.$on('noData', data => {
      console.log('noData')
      console.log(data)
      this.codeShow = false
      this.refreshMessage()
      this.code = ''
      this.version = ''
      this.status = null
      this.abiFile = ''
      this.abiEmpty = true
      this.contractAddress = ''
      this.errorMessage = ''
      this.contractName = ''
      this.content = ''
      this.bin = ''
    })
    Bus.$on('javaProjectComplie', data => {
      console.log('javaProjectComplie')
      console.log(data)
      this.contractName = data.contractName
      this.content = Base64.decode(data.contractSource)
      console.log(this.code)
      this.abiFile = data.contractAbi
      this.bin = data.contractBin
      this.data.contractVersion = data.contractVersion
      this.data.contractAddress = data.contractAddress
      this.data.contractName = data.contractName
      this.data.contractAbi = data.contractAbi
      this.data.bytecodeBin = data.bytecodeBin
      this.data.contractBin = data.contractBin
      this.data.contractId = data.contractId
      this.data.contractPath = data.contractPath
      this.data.contractSource = data.contractSource
      localStorage.setItem('isFinishCompile', 'no')
      this.compile()
    });
    [...document.querySelectorAll('.noBlur')].map((item) => {
      item.onmousedown = (event) => {
        event.preventDefault() // 点击按钮不会失去焦点（阻止默认）
      }
    })
  },
  methods: {
    // 活的查看权限
    async handleContractPermissions() {
      const ViewContractPermission = await this.getViewContractPermissions()
      const EditContractPermission = await this.getEditContractPermissions(1)
      if (EditContractPermission === false) {
        this.disabled = true
      } else {
        this.disabled = false
      }
    },
    // 获取查看权限
    async getViewContractPermissions() {
      try {
        const res = await getViewContractPermissions()
        const { data, code } = res
        if (code === 0) {
          // 空数组表示有权限
          const hasPermission = JSON.stringify(data) === '[]'
          // 缓存数据，不用每次请求后端
          this.ViewContractPermission = hasPermission
          return hasPermission
        } else {
          this.ViewContractPermission = false
          return false
        }
      } catch (error) {
        this.$messageOnce({
          message: '查看合约权限查询接口异常',
          type: 'error'
        })
      }
    },
    // 获取编辑权限
    async getEditContractPermissions() {
      try {
        const res = await getEditContractPermissions(1)
        const { data, code } = res
        if (code === 0) {
          // 空数组表示有权限
          const hasPermission = JSON.stringify(data) === '[]'
          // 缓存数据，不用每次请求后端
          this.EditContractPermission = hasPermission
          return hasPermission
        } else {
          this.EditContractPermission = false
          return false
        }
      } catch (error) {
        this.$messageOnce({
          message: '编辑合约权限查询接口异常',
          type: 'error'
        })
      }
    },
    onCloseUploadReport() {
      this.isShowUploadReport = !this.isShowUploadReport
    },
    // 上传
    onUploadReport() {
      this.isShowUploadReport = !this.isShowUploadReport
      this.$refs.uploadReport.getReportGroupList()
    },
    queryIsDeployedModifyEnable() {
      fetchIsDeployedModifyEnable()
        .then(res => {
          if (res.code === 0) {
            // 保存、编译、部署 开关。关了就只能看了，无法部署操作
            this.isDeployedModifyEnable = res.data
          } else {
            console.log(res)
            this.$messageOnce({
              message: this.$chooseLang(res.code),
              type: 'error',
              duration: 2000
            })
          }
        })
    },
    // 初始化编辑器
    initEditor: function() {
      const _this = this
      this.aceEditor = ace.edit(this.$refs.ace, {
        fontSize: 14,
        fontFamily: 'Consolas,Monaco,monospace',
        theme: this.themePath,
        mode: this.modePath,
        tabSize: 4,
        useSoftTabs: true
      })

      // 编辑器设置
      this.aceEditor.setOptions({
        enableSnippets: true,
        enableLiveAutocompletion: true,
        enableBasicAutocompletion: true,
        autoScrollEditorIntoView: true,
        copyWithEmptySelection: true
      })

      // 编辑器快捷键
      this.aceEditor.commands.addCommand({
        name: 'save',
        bindKey: { win: 'Ctrl-S', mac: 'Command-S' },
        exec: function(editor) {
          if (_this.data.contractStatus != 2) {
            _this.saveCode()
          }
        }
      })
      this.aceEditor.commands.addCommand({
        name: 'compile',
        bindKey: { win: 'Alt-C', mac: 'Option-C' },
        exec: function(editor) {
          if (!_this.contractAddress && !_this.disabled) {
            _this.compile()
          }
        }
      })
      this.aceEditor.commands.addCommand({
        name: 'deploying',
        bindKey: { win: 'Alt-D', mac: 'Option-D' },
        exec: function(editor) {
          if (!_this.contractAddress && _this.abiFile && _this.bin && !_this.disabled) {
            _this.deploying()
          }
        }
      })
      this.aceEditor.commands.addCommand({
        name: 'send',
        bindKey: { win: 'Alt-T', mac: 'Option-T' },
        exec: function(editor) {
          if (_this.abiFile && _this.bin && !_this.disabled) {
            _this.send()
          }
        }
      })
      const editor = this.aceEditor.alignCursors()
      this.aceEditor.getSession().setUseWrapMode(true)
      this.aceEditor.getSession().on('change', this.changeAce)
      this.aceEditor.on('blur', this.blurAce)
      this.aceEditor.resize()
    },
    // 离开编辑器逻辑
    blurAce: function(callback) {
      console.log('blur')
      const data = Base64.encode(this.content)
      // if (this.data.contractSource != data) {
      //     this.saveCode()
      // }
      //  this.saveShow = true;
      if (this.data.contractSource != data) {
        // console.log("合约改变弹框提示");
        this.$confirm(
          `${this.$t('text.unsavedContract')}？`,
          `${this.$t('text.title')}`,
          {
            confirmButtonText: this.$t('title.save'),
            center: true,
            type: 'warning',
            dangerouslyUseHTMLString: true
          }
        )
          .then(() => {
            this.saveCode()
          })
          .catch(() => {
            this.$messageOnce({
              type: 'info',
              message: this.$t('text.noSave')
            })
          })
      }
    },
    saveCode: function() {
      // 把内容转化成base64
      this.data.contractSource = Base64.encode(this.content)
      // 存储
      Bus.$emit('save', this.data)
    },
    resizeCode: function() {
      this.aceEditor.setOptions({
        maxLines:
                    Math.ceil(this.$refs.codeContent.offsetHeight / 17) - 1
      })
      this.aceEditor.resize()
    },
    dragDetailWeight: function(e) {
      const startY = e.clientY
      const infoHeight = this.infoHeight
      document.onmousemove = e => {
        const moveY = startY - e.clientY
        this.infoHeight = infoHeight + moveY
      }
      document.onmouseup = e => {
        document.onmousemove = null
        document.onmouseup = null
      }
      this.aceEditor.setOptions({
        maxLines:
                    Math.ceil(this.$refs.codeContent.offsetHeight / 17) - 1,
        minLines: 9
      })
    },
    upLoadAdr: function() {
      this.uploadFileAdrShow = true
    },
    uploadClose: function() {
      this.uploadFileAdrShow = false
    },
    uploadSuccess: function(val) {
      this.dialogVisible = true
      this.uploadAddress = val
    },
    sendSuccess: function(val) {
      this.sendConstant = val.constant
      this.uploadAddress = ''
      this.dialogVisible = false
      this.editorShow = true
      this.editorData = null
      this.editorData = val.resData
      this.editorInput = val.input
      this.editorOutput = val.data.outputs
      // if (val && val.contractAddress) {
      //     this.contractAddress = val.contractAddress;
      //     this.data.contractAddress = val.contractAddress;
      //     Bus.$emit("send", this.data)
      // }
    },
    editorClose: function() {
      this.editorShow = false
    },
    changeAce: function() {
      this.$nextTick(() => {
        this.content = this.aceEditor.getSession().getValue()
        //  console.log(this.code);
        // console.log(this.content);
        if (this.content.replace(/[\r\n\s]/g, '') == '') {
          this.aceEditor.setValue(this.code)
          this.content = this.aceEditor.getSession().getValue()
          return
        }
        var id = this.data.id
        // this.$nextTick(() => {
        if (Base64.decode(this.data.contractSource).length === this.content.length) {
          Bus.$emit('modifyState', {
            id: id,
            modifyState: false
          })
        } else {
          Bus.$emit('modifyState', Object.assign({}, this.data, {
            id: id,
            modifyState: true,
            contractSource: Base64.encode(this.content)
          }))
        }
        // })
      })
    },

    findImports: function(path) {
      this.contractList = this.$store.state.exercises.contractDataList
      const arry = path.split('/')
      const newpath = arry[arry.length - 1]
      let num = 0
      if (arry.length > 1) {
        const newPath = arry[0]
        const oldPath = arry[arry.length - 1]
        const importArry = []
        this.contractList.forEach(value => {
          if (value.contractPath == newPath) {
            importArry.push(value)
          }
        })
        if (importArry.length) {
          for (let i = 0; i < importArry.length; i++) {
            if (oldPath == importArry[i].contractName + '.sol') {
              return {
                contents: Base64.decode(
                  importArry[i].contractSource
                )
              }
            }
          }
        } else {
          return { error: 'File not found' }
        }
      } else {
        const newpath = arry[arry.length - 1]
        const newArry = []
        this.contractList.forEach(value => {
          if (value.contractPath == this.data.contractPath) {
            newArry.push(value)
          }
        })
        if (newArry.length > 1) {
          for (let i = 0; i < newArry.length; i++) {
            if (newpath == newArry[i].contractName + '.sol') {
              return {
                contents: Base64.decode(
                  newArry[i].contractSource
                )
              }
            }
          }
          for (let i = 0; i < this.contractList.length; i++) {
            if (newpath == this.contractList[i].contractName + '.sol') {
              return {
                contents: Base64.decode(this.contractList[i].contractSource)
              }
            } else {
              num++
            }
          }
          if (num) {
            return { error: 'File not found' }
          }
        } else {
          let num1 = 0
          for (let i = 0; i < this.contractList.length; i++) {
            if (newpath == this.contractList[i].contractName + '.sol') {
              return {
                contents: Base64.decode(this.contractList[i].contractSource)
              }
            } else {
              num1++
            }
          }
          if (num1) {
            return { error: 'File not found' }
          }
        }
      }
    },
    // 编译
    compile() {
      this.loading = true
      const version = this.$store.state.exercises.versionData
      if (version && version.net !== 0) {
        // 编译高版本
        this.compileHighVersion()
      } else {
        setTimeout(() => {
          // 编译低版本
          this.compileLowVersion()
        }, 500)
      }
    },
    // 高版本编译，具体原理不清楚，
    compileHighVersion(callback) {
      const that = this
      this.refreshMessage()
      this.contractList = this.$store.state.exercises.contractDataList
      const content = ''
      let output
      const input = {
        language: 'Solidity',
        settings: {
          outputSelection: {
            '*': {
              '*': ['*']
            }
          }
        }
      }
      input.sources = {}
      input.sources[this.contractName + '.sol'] = {}
      const libs = []
      input.sources[this.contractName + '.sol'] = {
        content: this.content
      }
      const w = this.$store.state.exercises.worker
      w.postMessage({
        cmd: 'compile',
        input: JSON.stringify(input),
        list: this.$store.state.exercises.contractDataList,
        path: this.data.contractPath
      })
      // w.addEventListener('message', function (ev) {
      w.onmessage = function(ev) {
        if (ev.data.cmd == 'compiled') {
          that.loading = false
          output = JSON.parse(ev.data.data)
          console.log('次数')
          if (output && output.contracts && JSON.stringify(output.contracts) != '{}') {
            that.status = 1
            if (output.contracts[that.contractName + '.sol']) {
              that.changeOutput(
                output.contracts[that.contractName + '.sol']
              )
            }
          } else {
            that.errorMessage = output.errors
            that.errorInfo = that.$t('contracts.contractCompileFail')
            that.loading = false
          }
        } else {
          console.log(ev.data)
          console.log(JSON.parse(ev.data.data))
        }
      }
      w.addEventListener('error', function(ev) {
        that.errorInfo = ev
        that.errorMessage = ev
        that.compileShow = true
        that.loading = false
      })
      console.log('wwww:', w)
    },
    // 低版本编译
    compileLowVersion: function() {
      // this.loading = true;
      try {
        // 引入solc-js
        const wrapper = require('solc/wrapper')
        var solc = wrapper(window.Module)
      } catch (error) {
        this.$messageOnce({
          type: 'error',
          message: this.$t('text.versionError'),
          duration: 3000
        })
      }
      this.refreshMessage()
      for (let i = 0; i < constant.COMPILE_INFO.length; i++) {
        this.compileinfo = this.compileinfo + constant.COMPILE_INFO[i]
      }
      this.contractList = this.$store.state.exercises.contractDataList
      const content = ''
      let output

      // 使用 solc-js
      const input = {
        language: 'Solidity',
        settings: {
          outputSelection: {
            '*': {
              '*': ['*']
            }
          }
        }
      }
      input.sources = {}
      input.sources[this.contractName + '.sol'] = {}
      const libs = []
      input.sources[this.contractName + '.sol'] = {
        content: this.content
      }
      try {
        // 执行编译
        output = JSON.parse(solc.compile(JSON.stringify(input), { import: this.findImports }))
      } catch (error) {
        // 编译问题
        this.errorInfo = error
        this.errorMessage = error
        this.compileShow = true
        this.loading = false
      }

      setTimeout(() => {
        // 如果编译成功后执行操作
        if (output && JSON.stringify(output.contracts) != '{}') {
          this.status = 1
          if (output.contracts[this.contractName + '.sol']) {
            this.changeOutput(
              output.contracts[this.contractName + '.sol']
            )
          }
        } else {
          // 编译失败执行操作
          this.errorMessage = output.errors
          this.errorInfo = this.$t('contracts.contractCompileFail')
          this.loading = false
        }
      }, 500)
    },
    changeOutput: function(obj) {
      // 改变output
      if (JSON.stringify(obj) !== '{}') {
        if (obj.hasOwnProperty(this.contractName)) {
          const compiledMap = obj[this.contractName]
          this.abiFileShow = true
          this.successInfo = this.$t('contracts.compileSuccess')
          this.abiFile = compiledMap.abi
          this.abiFile = JSON.stringify(this.abiFile)
          if (this.abiFile && this.abiFile != '[]') {
            this.abiEmpty = false
          }
          this.bin = compiledMap.evm.deployedBytecode.object
          this.bytecodeBin = compiledMap.evm.bytecode.object
          this.data.contractAbi = this.abiFile
          this.data.contractBin = this.bin
          this.data.contractSource = Base64.encode(this.content)
          this.$set(this.data, 'bytecodeBin', this.bytecodeBin)
          this.loading = false
          Bus.$emit('compile', this.data)
          this.setMethod()
          localStorage.setItem('isFinishCompile', 'yes')
        } else {
          this.$messageOnce({
            type: 'error',
            message: this.$t('contracts.conmileNameError')
          })
          this.errorInfo = this.$t('contracts.contractCompileFail')
          this.compileShow = true
          this.loading = false
        }
      } else {
        this.errorInfo = this.$t('contracts.contractCompileFail')
        this.compileShow = true
        this.loading = false
      }
    },
    // 导出java项目
    exportJava() {
      this.$store.dispatch('exercises/set_exportProject_show_action', true)
    },
    addContractAddress() {
      this.contractForm.contractAddress = ''
      this.addContractAddressVisible = true
    },
    closeContractAddress() {
      this.addContractAddressVisible = false
      this.contractForm.contractAddress = ''
    },
    sureContractAddress(formName) {
      this.$refs[formName].validate(valid => {
        if (valid) {
          if (this.contractForm.contractAddress == '' || this.contractForm.contractAddress == null) {
            this.$messageOnce({
              type: 'error',
              message: this.$t('contracts.contractAddressInput')
            })
          } else {
            this.addContractAddressVisible = false
            this.addContract()
          }
        } else {
          return false
        }
      })
    },
    // todo add contract address all hex string and start with 0x
    // 正则判断
    // todo 保存后加一个Close函数 刷新当前的ID数据
    addContract: function() {
      const reqData = {
        groupId: 1,
        contractName: this.data.contractName,
        contractPath: this.data.contractPath,
        contractSource: this.data.contractSource,
        contractAbi: this.data.contractAbi,
        contractBin: this.data.contractBin,
        bytecodeBin: this.data.bytecodeBin,
        contractAddress: this.contractForm.contractAddress
      }
      if (this.data.contractId) {
        reqData.contractId = this.data.contractId
      }
      Bus.$emit('save', reqData)
    },
    // 重置编译信息
    refreshMessage: function() {
      this.abiFileShow = false
      this.errorInfo = ''
      this.compileinfo = ''
      this.abiFile = ''
      this.contractAddress = ''
    },
    deploying: function() {
      if (!this.bytecodeBin) {
        this.$messageOnce({
          type: 'warning',
          message: this.$t('text.notHaveBin'),
          duration: 2000
        })
        return
      }
      if (JSON.parse(this.abiFile).length == 0 || !this.abiFile) {
        this.$messageOnce({
          type: 'error',
          message: this.$t('text.notHaveAbi')
        })
      } else {
        if (this.data.contractStatus && this.data && this.data.contractStatus == 2) {
          this.$confirm(this.$t('text.isRedeploy'))
            .then(_ => {
              this.dialogUser = true
            })
            .catch(_ => { })
        } else {
          this.dialogUser = true
        }
      }
    },
    userClose: function() {
      this.dialogUser = false
    },
    // methodId 签名
    setMethod: function() {
      const Web3EthAbi = web3
      const arry = []
      if (this.abiFile) {
        const list = JSON.parse(this.abiFile)
        list.forEach(value => {
          if (value.name && value.type == 'function') {
            const data = {}
            let methodId
            if (localStorage.getItem('encryptionId') == 1) {
              // 签名
              methodId = Web3EthAbi.smEncodeFunctionSignature({
                name: value.name,
                type: value.type,
                inputs: value.inputs
              })
            } else {
              // 签名
              console.log(Web3EthAbi)
              methodId = Web3EthAbi.encodeFunctionSignature({
                name: value.name,
                type: value.type,
                inputs: value.inputs
              })
            }
            // 截取长度
            data.methodId = methodId.substr(0, 10)
            data.abiInfo = JSON.stringify(value)
            data.methodType = value.type
            arry.push(data)
          } else if (value.name && value.type == 'event') {
            const data = {}
            let methodId
            if (localStorage.getItem('encryptionId') == 1) {
              methodId = Web3EthAbi.smEncodeEventSignature({
                name: value.name,
                type: value.type,
                inputs: value.inputs
              })
            } else {
              methodId = Web3EthAbi.encodeEventSignature({
                name: value.name,
                type: value.type,
                inputs: value.inputs
              })
            }
            data.methodId = methodId.substr(0, 10)
            data.abiInfo = JSON.stringify(value)
            data.methodType = value.type
            arry.push(data)
          }
        })
        if (arry.length) {
          this.addAbiMethod(arry)
        }
      }
    },
    addAbiMethod: function(list) {
      // 编译会执行这个方法
      const data = {
        groupId: 1,
        methodList: list
      }

      // 接口
      addFunctionAbi(data).then(res => {
        if (res.code === 0) {
          console.log('method 保存成功！')
        } else {
          this.$messageOnce({
            message: this.$chooseLang(res.code),
            type: 'error',
            duration: 2000
          })
        }
      }).catch(err => {
        console.log('addFunctionAbi')
        this.$messageOnce({
          message: err.data || this.$t('text.systemError'),
          type: 'error',
          duration: 2000
        })
      })
    },
    deployContract($event) {
      var val = $event[0]; var cns = $event[1]
      if (val && !val.userId) {
        this.$messageOnce({
          type: 'info',
          message: this.$t('contracts.addPrivateKeyInfo')
        })
        router.push('/privateKeyManagement')
        return
      }
      this.loading = true
      const reqData = {
        groupId: 1,
        contractBin: this.bin,
        bytecodeBin: this.bytecodeBin,
        contractAbi: this.abiFile,
        contractSource: Base64.encode(this.content),
        user: val.userId,
        contractName: this.contractName,
        contractId: this.data.contractId,
        contractPath: this.data.contractPath,
        account: localStorage.getItem('user')
      }
      this.version = val.version
      if (val.params.length) {
        reqData.constructorParams = val.params
      }
      getDeployStatus(reqData)
        .then(res => {
          this.loading = false
          if (res.code === 0) {
            this.abiFileShow = true
            this.status = 2
            this.contractAddress = res.data.contractAddress
            this.successInfo = this.$t('contracts.deploySuccess')
            this.abiFile = res.data.contractAbi
            this.bin = res.data.contractBin
            this.$messageOnce({
              message: this.$t('contracts.contractDeploySuccess'),
              type: 'success'
            })
            this.data.contractAbi = this.abiFile
            this.data.contractBin = this.bin
            this.data.contractSource = Base64.encode(this.content)
            this.data.contractAddress = this.contractAddress
            this.data.contractVersion = this.version
            if (cns.saveEnabled) {
              this.queryRegisterCns(val, cns)
            }
            Bus.$emit('deploy', this.data)
          } else {
            this.status = 3
            this.$messageOnce({
              message: this.$chooseLang(res.code),
              type: 'error',
              duration: 2000
            })
          }
        })
        .catch(err => {
          console.log('getDeployStatus')
          this.status = 3
          this.loading = false
          this.$messageOnce({
            message: err.data || this.$t('text.systemError'),
            type: 'error',
            duration: 2000
          })
        })
    },
    queryRegisterCns(val, cns) {
      const param = {
        groupId: 1,
        contractName: this.contractName,
        version: cns.version,
        contractAbi: this.abiFile,
        userAddress: val.userId,
        saveEnabled: true,
        contractAddress: this.contractAddress,
        cnsName: cns.cnsName,
        contractPath: this.data.contractPath
      }
      registerCns(param)
        .then(res => {
          if (res.code === 0) {
            this.queryFindCnsInfo()
          } else {
            this.$messageOnce({
              message: this.$chooseLang(res.code),
              type: 'error'
            })
          }
        })
    },
    foldInfo: function(val) {
      this.successHide = val
    },
    send: function() {
      console.log(JSON.parse(this.abiFile))
      if (JSON.parse(this.abiFile).length == 0 || !this.abiFile) {
        this.$messageOnce({
          type: 'error',
          message: this.$t('text.notHaveAbi')
        })
      } else {
        this.dialogVisible = true
      }
    },
    handleClose: function() {
      this.dialogVisible = false
    },
    sendClose: function() {
      this.$refs.send.close()
    },
    showAbiText() {
      this.showAbi = !this.showAbi
      if (this.$refs['showAbiText'].style.overflow === 'visible') {
        this.$refs['showAbiText'].style.overflow = 'hidden'
      } else if (this.$refs['showAbiText'].style.overflow === '' || this.$refs['showAbiText'].style.overflow === 'hidden') {
        this.$refs['showAbiText'].style.overflow = 'visible'
      }
    },
    showBinText() {
      this.showBin = !this.showBin
      if (this.$refs['showBinText'].style.overflow === 'visible') {
        this.$refs['showBinText'].style.overflow = 'hidden'
      } else if (this.$refs['showBinText'].style.overflow === '' || this.$refs['showBinText'].style.overflow === 'hidden') {
        this.$refs['showBinText'].style.overflow = 'visible'
      }
    },
    showHover() {

    },
    hiddenHover() {

    },
    collapse() {
      this.showCompileText = !this.showCompileText
      if (this.showCompileText) {
        this.infoHeight = 250
      } else if (!this.showCompileText) {
        this.infoHeight = 50
      }
      this.$nextTick(() => {
        this.resizeCode()
      })
    },
    copyKey(val) {
      if (!val) {
        this.$messageOnce({
          type: 'fail',
          showClose: true,
          message: this.$t('text.copyErrorMsg'),
          duration: 2000
        })
      } else {
        this.$copyText(val).then(e => {
          this.$messageOnce({
            type: 'success',
            showClose: true,
            message: this.$t('text.copySuccessMsg'),
            duration: 2000
          })
        })
      }
    },
    severityColor(item) {
      const key = item.severity
      switch (key) {
        case 'error':
          return '#F56C6C'
          break

        case 'warning':
          return '#E6A23C'
          break
      }
    },
    queryFindCnsInfo() {
      const param = {
        // groupId: 1,
        groupId: 1,
        contractAddress: this.data.contractAddress
      }
      findCnsInfo(param)
        .then(res => {
          // 获取CNS 信息，目前没有发现作用
          const { code, data } = res
          if (code === 0) {
            if (data) {
              this.reqVersion = data.version
              this.cnsName = data.cnsName
            } else {
              this.reqVersion = ''
              this.cnsName = ''
            }
          } else {
            this.$messageOnce({
              type: 'error',
              message: this.$chooseLang(res.code)
            })
          }
        })
    },
    handleRegisterCns() {
      this.mgmtCnsItem = this.data
      this.mgmtCnsVisible = true
    },
    mgmtCnsResultSuccess() {
      this.queryFindCnsInfo()
      this.mgmtCnsVisible = false
    },
    mgmtCnsResultClose() {
      this.mgmtCnsVisible = false
    },
    handleChange(val) {
      console.log(val)
    }
  }
}
</script>
<style lang="scss" scoped>
.contract-code {
    height: 100%;
    border-left: 1px solid #eee;
    box-sizing: border-box;
}
.changeActive {
    padding-left: 0 !important;
}
.contract-code-head {
    width: 100%;
    height: 48px;
    line-height: 48px;
    border-bottom: 2px solid #e7ebf0;
    background-color: #fff;
    overflow: hidden;
}
.contract-code-done {
    display: inline-block;
    margin-right: 10px;
    cursor: pointer;
}
.contract-code-done i {
    vertical-align: middle;
}
.contract-code-done span {
    font-size: 12px;
    color: #9da2ab;
    vertical-align: middle;
}
.contract-no-content {
    border-left: 1px solid #e7ebf0;
    height: calc(100% - 50px);
    box-sizing: border-box;
}
.contract-code-content {
    border-left: 1px solid #e7ebf0;
    height: calc(100% - 50px);
    box-sizing: border-box;
}
.contract-code-mirror {
    width: 100%;
    height: 70%;
}
.contract-info {
    position: relative;
    padding-top: 20px;
    text-align: left;
    border-top: 1px solid #ddd;
    box-sizing: border-box;
    overflow: auto;
    padding-left: 5px;
}
.contract-info-content {
    height: 100%;
    overflow-y: scroll;
    box-sizing: border-box;
}
.contract-code-title {
    float: left;
    font-weight: bold;
    font-size: 18px;
    color: #36393d;
    padding-left: 20px;
}
.contract-code-handle {
    float: right;
    padding-right: 20px;
}
.contract-info-title {
    text-align: center;
}
.move {
    position: absolute;
    width: 100%;
    height: 3px;
    top: 0;
    left: 0;
    z-index: 9999;
    cursor: s-resize;
}
.contract-info-title i {
    padding-left: 8px;
    font-size: 10px;
    color: #aeb1b5;
    cursor: pointer;
}
.contract-info-title span {
    font-size: 16px;
    font-weight: bold;
    color: #36393d;
}
.contract-info-list {
    padding: 5px 20px;
    width: 90%;
    margin: 0 auto;
    border: 1px solid #e8e8e8;
    border-bottom: none;
    position: relative;
}
.contract-info-list-title {
    display: inline-block;
    width: 105px;
    vertical-align: top;
}
.contract-info-list-title::after {
    display: block;
    content: "";
    clear: both;
}
.ace-editor {
    height: 100% !important;
    position: relative;
    text-align: left;
    letter-spacing: 0.1px;
    text-rendering: geometricPrecision;
    font-feature-settings: "liga" 0;
    font-variant-ligatures: none;
    font: 14px / normal "Monaco", "Menlo", "Ubuntu Mono", "Consolas",
        "source-code-pro", monospace !important;
}
.ace-editor >>> .ace_print-margin {
    display: none;
    text-rendering: geometricPrecision;
}
.infoHide {
    height: calc(100% - 50px);
}
.code-spread {
    position: absolute;
    width: 33px;
    height: 33px;
    line-height: 33px;
    left: 412px;
    bottom: 0;
    border: 1px solid #e8e8e8;
    color: #aeb1b5;
    background-color: #fff;
    text-align: center;
    z-index: 9999;
    cursor: pointer;
}
.code-spread i {
    font-size: 12px;
}
.contract-info {
    background-color: #fff;
}
.titleActive {
    padding-left: 40px;
}
.send-dialog >>> .el-dialog--center .el-dialog__body {
    padding: 5px 25px 20px;
}
.showText {
    display: inline-block;
    width: calc(100% - 120px);
    word-wrap: break-word;
    max-height: 73px;
    overflow: hidden;
}
.visibility-wrapper {
    position: absolute;
    bottom: 10px;
}
.copy-public-key {
    float: right;
}
.contract-font {
    color: #777;
    cursor: pointer;
}
.contract-font:hover {
    color: #111;
}
.contract-font:active {
    color: #111;
}
.contract-font:visited {
    color: #111;
}
.error-item >>> .el-collapse {
    border-bottom: 1px solid #fff;
    border-top: 1px solid #fff;
}
.error-item >>> .el-collapse-item__header {
    color: inherit;
    background-color: inherit;
    height: inherit;
    line-height: inherit;
    border-bottom: 1px solid #fff;
    font-size: 12px;
    font-weight: none;
}
.error-item >>> .el-collapse-item__content {
    /* background-color: #fff; */
}
.error-item >>> .el-collapse-item__wrap {
    border-bottom: 1px solid #fff;
}
.uploadReportIcon {
  position: relative;
  margin-right: 4px;
  /* top: 1px; */
}
.uploadReportBtn {
    @include UploadReportBtn();
}
</style>
